home *** CD-ROM | disk | FTP | other *** search
/ Aminet 19 / Aminet 19 (1997)(GTI - Schatztruhe)[!][Jun 1997].iso / Aminet / comm / cnet / gu40pack.lha / gu40pack / GU40_Coders < prev    next >
Text File  |  1997-03-21  |  29KB  |  581 lines

  1. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  2.  Proper Usage of GetUser & GetScratch commands in CNet Amiga! (3.05c/4.26b+)
  3. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  4.  
  5.     Before I explain how to use the GETUSERS as such, I'd like to remind you
  6. all that these values(both "short" and "long") can also be used with the MCI
  7. {V } command, whereby you specify a GETUSER value right after the "V", as in
  8. these examples:
  9.                     {v1} ---------> Print User's Handle.
  10.                     {v15} --------> The User's Access Group.
  11.                     {v1200016} ---> The User's Age In Years.
  12.                     {v1100468} ---> Number of ROWS on User's Screen.
  13.                     {v2400960} ---> Total Uploaded KiloBytes to the System.
  14.                     ^
  15.                 Control-Q
  16.  
  17.     Additionally, these values can be used with the {L }, {M }, and {T } MCI
  18. commands to LOAD, perform MATH, or TEST the contents of any getuser location.
  19.  
  20.     Using these "short" GETUSER values, you can create files that can pull
  21. various pieces of information on the CURRENT user, however, if you wish to
  22. use these values to obtain information on OTHER users, you will have to use
  23. the GETSCRATCH command.
  24.  
  25.     NOTE, however, that not ALL of these values can be used with GETSCRATCH.
  26. Only those marked with an "s" in the first column will return valid data. you
  27. will have to use the LONG, 7-Digit values to obtain any info NOT listed above
  28. as being flagged by an "s", or you will have to use the ADDRESS CNETREXX port
  29. command to extrapulate the info(using GETUSER), while the user is online. More
  30. info on these areas can be found in the other text files.
  31.  
  32.     Before you can use the GETSCRATCH command, you have to load the user in
  33. question's information into a temporary buffer called the SCRATCH BUFFER.
  34. You do this by using the LOADSCRATCH command, which takes an ID Number for
  35. it's sole NEEDED argument, like this:
  36.  
  37. LOADSCRATCH 5
  38.  
  39.     The above command will load all pertinent information pertaining to the
  40. user using ID Number 5 on your system. You need to be aware that when you use
  41. the LOADSCRATCH command, you are putting a LOCK on the Account ID. What this
  42. means is that NO OTHER FILE, and NO OTHER USER may use this accounts data,
  43. INCLUDING the user which HOLDS that ID. If the user with this ID happens to
  44. be ONLINE when your program LOCKS the account, that user's port will seem to
  45. freeze up, until your program has finished doing what it needs to do. (This
  46. same kind of LOCK occurs when you use the EA command to edit a user's account
  47. while they are online as well).
  48.  
  49.     After the account has been LOCKED, you can then use GETSCRATCH to obtain
  50. any values you wish, using either the "short" or the "long" values listed in 
  51. the included lists.
  52.  
  53.     It is recommended that you use a SHORT getuser value whenever possible,
  54. because these commands are defined INTERNALLY by CNet itself, so will almost
  55. ALWAYS point to the correct data, while the Long, 7-digit values COULD change
  56. over time as Ray makes more and more modifications to the internal structures.
  57.  
  58.     When you are FINISHED grabbing the info needed, you MUST remember to 
  59. UNLOCK the account using the SAVESCRATCH command. This will insure that any 
  60. other program that needs to get into that account CAN, and will also allow 
  61. that user to continue on with his/her business(if they were ONLINE), or that 
  62. they will be ABLE to LOGON the next time they DO call.
  63.  
  64.     By FORGETTING to UNLOCK an account, you are releasing a veritable bomb
  65. into your system, because if either another program or THAT user tries to
  66. access the account, the port that attempted the access will be LOCKED UP!
  67. The only way to recover the port is through a complete System Reset, or by
  68. running a script similar to the following:
  69.  
  70.                 /* Unlock ALL User Accounts */
  71.                   options results
  72.                   getuser 2400088 ; accounts=result
  73.                   do i=1 to accounts
  74.                     savescratch (-i)
  75.                   end i
  76.                 /* End */
  77.  
  78.     The SAVESCRATCH command also takes a sole NEEDED argument, which should
  79. preferably be the SAME ID Number you used in the LOADSCRATCH command. If all
  80. you did was to READ data out of the account, then you can use a NEGATIVE ID
  81. Number value to simply REMOVE the LOCK on the account, like this:
  82.  
  83. SAVESCRATCH (-5)
  84.  
  85.     If, however, you made CHANGES to the data and wish these CHANGES to be
  86. SAVED to the account BEFORE it is UNLOCKED, then supply a POSITIVE value:
  87.  
  88. SAVESCRATCH 5
  89.  
  90.     Note that when NEGATIVE values are used, they should be given inside of
  91. parenthesis, else the UNLOCK'ing may NOT be successfull.
  92.  
  93.     If your file will be executed by the CURRENTLY ONLINE user, then use the 
  94. PUTUSER command, in conjunction with the SETOBJECT command when you wish to 
  95. make CHANGES to their data, like this:
  96.  
  97. SETOBJECT "His unlisted phone number is: 823-9892"
  98.  
  99. PUTUSER 9
  100.  
  101.     The above example places the text shown in the "SysOp Comment" for the
  102. current user online. 
  103.  
  104.     If, however, your file will be run via AutoMaintenance, or by some OTHER
  105. user manually, you'd need to use the Scratch Buffer. Using the PUTSCRATCH and
  106. SETOBJECT commands, like this:
  107.  
  108. LOADSCRATCH 5
  109.  
  110. SETOBJECT "His unlisted phone number is: 823-9892"
  111.  
  112. PUTSCRATCH 9
  113.  
  114. SAVESCRATCH 5
  115.  
  116.     Notice the use of PUTSCRATCH, instead of PUTUSER. Remember that when you
  117. are using the SCRATCH BUFFER, all pertinent commands should END in "SCRATCH"
  118.  
  119.         LOADSCRATCH, GETSCRATCH, PUTSCRATCH, and SAVESCRATCH
  120.  
  121.     The SETOBJECT command is the only command that is used for BOTH fields
  122. of operation: Current User versus Scratch User.
  123.  
  124.     Lastly, what happens if you specify a DIFFERENT ID Number for SAVESCRATCH
  125. than you used in LOADSCRATCH?  Well, you'd be making a DUPLICATE copy of the
  126. SCRATCH BUFFER into the NEW ID Number. What?!? Look at this example:
  127.  
  128. LOADSCRATCH 1
  129. SAVESCRATCH (-1)
  130. SAVESCRATCH 2
  131. SAVESCRATCH 3
  132.  
  133.     If the above program was run, your first three Accounts would all hold
  134. IDENTICAL information to that shown in ID # 1's account. This is ONE way to
  135. EASILY make a NEW account. It saves having to sign on as a NEW user, when
  136. all you'd THEN have to do would be to EA the new account and change certain
  137. key pieces of info, notably: Serial ID Number, Handle, Real Name, and perhaps
  138. the Password.
  139.  
  140.     When writing scripts to automatically update pieces of info in numerous
  141. accounts at once, try using the following technique:
  142.  
  143. /**/;options results
  144. getuser 2400088 ; accounts=result
  145. do i=1 to accounts
  146.   loadscratch i ; status=result
  147.   getscratch 1  ; handle=result
  148.   if status=0 | handle="!" then do
  149.     savescratch (-i) ; iterate i ; end
  150.  
  151.   /*                                  */
  152.   /*  Enter your work commands here.  */
  153.   /*                                  */
  154.  
  155.   savescratch i
  156. end i
  157. /* END */
  158.  
  159.     Using a DO-Loop allows you to process through ALL your user accounts. The
  160. 2400088 value tells the script HOW MANY accounts you have to process. The
  161. "status" and "handle" variables allow you to perform a "pre-check" on the
  162. given account to make sure it's a valid account. "status" returns a "1" if
  163. the information was successfully loaded, or else a "0" if there was a problem
  164. loading the data. One possible problem might be if ANOTHER file was currently
  165. working on that account(ie, the account was locked already). If the "handle"
  166. variable contains a "!" (exclamation point), this means that that account has
  167. been KILLED (or DELETED) from the system. (Use my ReVive utility to attempt
  168. to reincarnate that account). If either "status=0", or "handle='!'", then the
  169. loop will SKIP OVER that account, but will UNLOCK the account using the "-i"
  170. value first. If "status=1" and "handle" equals something OTHER than "!", then
  171. the script continues to the "work" portion, which is supplied by you. After 
  172. your portion, the "savescratch i" command is used to both SAVE and UNLOCK the
  173. account, before proceeding to the next account.
  174.  
  175.     Note that when the account is SAVED using SAVESCRATCH <id>, the ENTIRE
  176. account is saved back to disk and NOT just the info you changed. Being as the
  177. LOADSCRATCH command reads the userdata directly from disk, if a user signs on
  178. to the board, then makes a change to one or more of their personal infos, if
  179. a script is run that uses the SCRATCH commands, if the account is SAVED, it
  180. is possible that the changes made by the user when they logged on may NOT be
  181. saved to disk(as if the user never changed the info).
  182.  
  183.     Your "work" portion would contain commands like GETSCRATCH, IF-THEN's,
  184. SETOBJECT's, and PUTSCRATCH commands. For instance, the following "work"
  185. portion could be used to copy ALL user's REAL NAMES into their HANDLE fields,
  186. in the event you ran a BBS that did NOT allow for the usage of aliases, or
  187. handles(Note that the following would have to be INSERTED into the above
  188. listed framework BEFORE being executed, else errors will occur):
  189.  
  190. /* Work STARTS Here */
  191.   getscratch 1 ; handle=result
  192.   getscratch 3 ; realname=result
  193.   if handle=realname then do
  194.     savescratch (-i) ; iterate i ; end
  195.   setobject realname
  196.   putscratch 1
  197. /* Work ENDS Here */
  198.  
  199.     The above uses GETSCRATCH to obtain both the real name and handle of the
  200. user account being processed. If the two contain identical information, then
  201. the account is UNLOCKED, and the loop proceeds to the next account...
  202.  
  203.     If, however, the two differ, then the SETOBJECT and PUTSCRATCH commands
  204. are used to copy the REAL NAME into the HANDLE buffer. The SAVESCRATCH that
  205. is used in the "framework" coding above then SAVES and UNLOCKS that account
  206. before proceeding to the next account.
  207.  
  208.     As one last example, the following coding could be used to DISABLE the
  209. "SuperUser" flag in any account where the Access Group was LESS than 30, while
  210. at the same time ENABLING the "SuperUser" flag if the Access Group EQUALS 30
  211. or 31. (The "SuperUser" flag will be used to control who has access to certain
  212. SysOp functions pertaining to upcoming Internet enhancements made by Ray):
  213.  
  214. /* Work STARTS Here */
  215.   getscratch 15 ; access=result
  216.   getscratch 1401380 ; abit1=reverse(d2c(result,4))
  217.   superuser=bittst(abit1,0)
  218.   if (access<30 & superuser=0) | (access>29 & superuser=1) then do
  219.     savescratch (-i) ; iterate i ; end
  220.   if access<30 then abit1=bitclr(abit1,0)
  221.     else abit1=bitset(abit1,0)
  222.   setobject c2d(reverse(abit1),4)
  223.   putscratch 1401380
  224. /* Work ENDS Here */
  225.  
  226.     Here, we grab the users Access group, then pull the second priviledge
  227. block and extrapolate the "SuperUser" flag, which will equal a 0 if they
  228. do NOT have the flag set, or a 1 if they DO have it set.
  229.  
  230.     If their access is LOW and the flag is NOT set, or if their access is
  231. HIGH and they DO have the flag set, then no work is needed, so we UNLOCK the
  232. account and continue through the loop.
  233.  
  234.     If changes are needed, we use the BitSET() function to ENABLE the flag if
  235. the user's Access is HIGHER than 29, else we use the BitCLR() function to
  236. DISABLE the flag if their Access is LOWER than 30. We finish the operation by
  237. reconstructing the priviledge block, then write it into memory by using the
  238. PUTSCRATCH command. The SAVESCRATCH given in the "framework" coding above is
  239. used to SAVE the info to disk as well as UNLOCKING the account before it
  240. continues to the next account ID Number.
  241.  
  242.     Well, that concludes the basic usage of the GetUsers and Scratch Buffer
  243. of CNet Amiga. The remainder of this document is intended for SEASONED ARexx
  244. enthusiasts ONLY, and is NOT meant for amateurs. Please HEED this warning,
  245. else you could SERIOUSLY damage the system structures used on your bbs.
  246.  
  247. /**************************************************************************/
  248.                             The End (For Now!)
  249.  
  250.  o=======================================================================o
  251.  | !CAUTION!               -= SERIOUS WARNING =-               !CAUTION! |
  252.  |                                                                       |
  253.  |  The following is meant for EXPERIENCED ARexx Coders ONLY! If you do  |
  254.  | NOT have a FIRM grasp on ARexx, then please DO NOT ATTEMPT any of the |
  255.  |                    following programming examples!                    |
  256.  o=======================================================================o
  257.  
  258.     Getuser values given in the examples below pertain to BOTH v3.05c AND
  259. v4.26b+ of CNet Amiga, unless specifically stated otherwise...
  260.  
  261.     The value returned using the x6xxxxx getuser value is of no use to us if
  262. we're dealing with a STRUCTURE. We must read the value in as a x4xxxxx value
  263. instead. As an example, let's take a look at the SELECT BUFFER structure,
  264. which has a getuser value of 1601978. Here's a snip of what that structure
  265. looks like, as shown in the v4.26b "subs.h" file, as we'll need this info
  266. when we wish to work with any of the data WITHIN that structure:
  267.  
  268. struct SelectType {         /* Select list */
  269.     long    Size;
  270.     char    Title   [32];
  271.     char    Location[96];   /* physical path to file */
  272.     short   Base;           /* physical subboard # */
  273.     UBYTE   SDownFiles;     /* Which accounting schedule ? */
  274.     UBYTE   SDownBytes;
  275.     UBYTE   temp_rem;       /* DS from DS list!! */
  276.     UBYTE   CDROM;          /* Copy to CDROMpath before download? */
  277.     BYTE    FreeStuff;
  278.     UBYTE   AutoKill;       /* 1==mark for amaint deletion when downloaded
  279.                                2==Yank, 3==DELETE when unselected */
  280.     long    ByteDownload;   /* credits to subtract when this */
  281.     short   FileDownload;   /* item is downloaded ... */
  282.                             /* makes * faster by being here */
  283.     struct  IsDate ADate;   /* utility ... AO adopt dates? */
  284.     ULONG   Number;         /* item number */
  285. };
  286.  
  287.     The first thing we need to do is "map out" the structure, to find the
  288. LENGTH of each data item WITHIN this structure. Below is a table listing
  289. this info:
  290.  
  291.             Name            Start   End     Type    Length
  292.            ------------------------------------------------
  293.             Size            1       4       long    4
  294.             Title           5       36      char    32
  295.             Location        37      132     char    96
  296.             Base            133     134     short   2
  297.             SDownFiles      135     135     UBYTE   1
  298.             SDownBytes      136     136     UBYTE   1
  299.             temp_rem        137     137     UBYTE   1
  300.             CDROM           138     138     UBYTE   1
  301.             FreeStuff       139     139     BYTE    1
  302.             AutoKill        140     140     UBYTE   1
  303.             ByteDownload    141     144     long    4
  304.             FileDownload    145     146     short   2
  305.             ADate           147     152     struct  6
  306.             Number          153     156     long    4
  307.            ------------------------------------------------
  308.  
  309.     We use the info given previously in the Intro file to find the LENGTH of
  310. each data item. Note the "ADate" is a structure in itself, but it's a DATE 
  311. format structure, and from the Intro, we know ALL dates are 6 bytes in length, 
  312. which makes it even easier.
  313.  
  314.     As a check to make sure we've constructed the table correctly, you can
  315. ADD all the values in the "Length" column. This value should MATCH the last
  316. value in the "End" column. This value determines the OVERALL LENGTH of the
  317. entire structure, which happens to be 156 bytes in this example.
  318.  
  319.     After these steps have been completed, we're ready to start working with
  320. this information, and can now start the coding necessary. The first thing we
  321. need to do is change the 1601978 value into a x4xxxxx value: 1401978. That's
  322. the easy part. We then read in this value as a getuser, as shown below:
  323.  
  324.          pb=null() ; getuser 1401978 ; start=offset(pb,result)
  325.  
  326.     The "pb" variable is a starting point in memory we can use. It contains 
  327. the "null" address, which is "$00000000". Using the returned result of our 
  328. getuser, we can then use the OFFSET() function(which is located in the
  329. "rexxsupport.library") to create a "start" variable. This "start" variable 
  330. contains the starting memory location of the Download Select Buffer, in 
  331. character format. If we wanted to work with the second item in the select 
  332. list, we would add 156 to "result", so the line looked like this:
  333.  
  334.          pb=null() ; getuser 1401978 ; start=offset(pb,result+156)
  335.  
  336.     We could use a DO-Loop and work with each file in sequence, until we
  337. had completed whatever action we began. (Another getuser value, 1209644,
  338. tells us how many items are IN the select buffer).
  339.  
  340.     We can now read in the entire 156 bytes into ONE variable, and then use
  341. the PARSE command to get the info we need:
  342.  
  343.      struct=import(start,156)
  344.  
  345.      parse var struct size 5 title 37 location 133 base 135 sdownfiles 136,
  346.                       sdownbytes 137 temp 138 cdrom 139 freestuff 140,
  347.                       autokill 141 bytedownload 145 filedownload 147,
  348.                       adate 153 number
  349.  
  350.     In the above PARSE statement, the commas at the ENDS of each line are
  351. CONTINUATION markers, meaning what comes on the NEXT line is actually a
  352. CONTINUATION of the above line. Note the numbers that FOLLOW each variable
  353. name are the START values for the FOLLOWING variable, and are taken right
  354. out of that table we made above, so "title" starts at the 5th byte, while
  355. "location" starts at the 37th byte, etc.
  356.  
  357.     Using the PARSE command is not the ONLY step involved. Each TEXT variable
  358. will ALSO have to be STRIP()'ed of any excess "00"x's that may have been used
  359. to pad out that data to the proper lengths. You will also need to use the
  360. C2D() function to CONVERT the CHARACTER values into DECIMAL values if the
  361. data is a NUMERIC value. Here's how the first six variables would look coded
  362. to be as "clean and neat" as possible:
  363.  
  364.                       size=c2d(size,4)
  365.  
  366.                      title=strip(title,,"00"x)
  367.  
  368.                   location=strip(location,,"00"x)
  369.  
  370.                       base=c2d(base,2)
  371.  
  372.                 sdownfiles=c2d(sdownfiles)
  373.  
  374.                 sdownbytes=c2d(sdownbytes)
  375.  
  376.     Again, we use the table we made above to find the lengths of the NUMERIC
  377. data. When a numeric value is NOT given in the C2D() function, the default
  378. value of "1" will be used.
  379.  
  380. -----------------------------------------------------------------------------
  381.  
  382.     The following is given for EXPERT users, and makes your work a bit faster
  383. as well as taking up less code:
  384.  
  385.      pb=null() ; getuser 1401978 ; struct=import(offset(pb,result),156)
  386.  
  387.      parse var struct size 5 title"00"x 36 location"00"x 131 base 133,
  388.                       sdownfiles 134 sdownbytes 135 temp 136 cdrom 137,
  389.                       freestuff 138 autokill 139 bytedownload 143,
  390.                       filedownload 145 adate 151 number
  391.  
  392.     Note the addition of the "00"x to both the "title" and "location" variable
  393. names. This way, we can do an automatic STRIP() NOW, without having to worry
  394. about it later. What makes this technique a bit more complicated is the fact
  395. that the NUMERIC values we use will DIFFER from those shown in the table we
  396. have been using. Note the "5" is the same, but we're using "36", instead of
  397. "37". This is because we are reading one "00"x, in ADDITION to the "title".
  398. Note that the "131" is two less than the stated value of "133". This is
  399. because the "00"x that we have following "location" makes the SECOND "00"x
  400. that is being read by the PARSE command, so we need to SUBTRACT TWO from
  401. every following value.
  402.  
  403.     Simply put(if it CAN be simply put), the NUMERIC START VALUE will be
  404. the STATED START VALUE(from our table above), minus the number of "00"x's
  405. that PRECEED the variable name in the PARSE command. (We use 36, because 1
  406. "00"x appears BEFORE the "title", so 37 - 1 = 36. We use 131, because there
  407. are 2 "00"x's that appear before the "base" name, thus 133 - 2 = 131, etc.)
  408.  
  409.     Again, the above is meant for EXPERT users, so don't be dismayed if you
  410. happen to be thoroughly LOST about now. Simply use the first method that was
  411. discussed above, followed by the individual STRIP()'ing and/or C2D()'ing
  412. that may be necessary.
  413.  
  414. -----------------------------------------------------------------------------
  415.  
  416.     Finally, let's take a look at some SPECIFIC values in the GetUser list:
  417.  
  418. ======================================================================
  419.    v3.05c   |   The START of the MainPort STRUCTURE      |  v4.26b+
  420. ============|============================================|============
  421.    1601850  | Pointer to cnp, MainPort                   |  1601850
  422. ------------+--------------------------------------------+------------
  423.             |    The START of the PortData STRUCTURE     |
  424. ------------+--------------------------------------------+------------
  425.    2624286  | PortData; (*PortZ[100]) Struct - Port 0    |  2626974
  426.         +4  |                                            |       +4
  427.         |   | (Pointer in MEMORY where struct is stored) |       |
  428.         +4  |                                            |       +4
  429.    2624682  | PortData; (*PortZ[100]) Struct - Port 99   |  2627370
  430. ======================================================================
  431.  
  432.     These values can give us the needed START MEMORY addresses for ALL the
  433. getuser Values given in the "GU40_Longs" listing. The "MainPort" value can
  434. be used to grab any value shown as a 2xxxxxx getuser, while the "PortData"
  435. values govern all the 1xxxxxx getuser values.
  436.  
  437.     The CNet Manual talks about using the "ADDRESS CNETREXXport" command to
  438. communicate with other CNet ports, either from another CNet Port, or from
  439. an external ARexx script. This command has it's uses, but also has some BIG
  440. drawbacks. If YOUR ARexx file tries to address another port that is ALREADY
  441. RUNNING an ARexx file, then YOUR application is PUT ON HOLD, until THEIR
  442. program has exited. What this means is YOUR port would be LOCKED OUT, until
  443. such a time as your file could get CONTROL of THEIR port. Another problem
  444. comes when your file tries to address a port that is in the middle of a file
  445. transfer(upload or download), as CNet places a LOCK on a port before it will
  446. initiate any file transfer. AGAIN, you'd be locked out, until the completion
  447. of the file transfer.
  448.  
  449.     If all you WANT to do is READ a certain value from THEIR config data, the
  450. POINTERS above are what you really want to use. Let's say you're wondering if
  451. Port # 1 is HIDING from you(on Port # 0). [This DIFFERS from the WHO display,
  452. which only shows you which ports YOU are hiding from!] Here's all we have to
  453. do to find out this information:
  454.  
  455. 1: Hiding capability is part of the "PortData" structure, which means we
  456.    need to get the START value of Port # 1's "PortData", which the above
  457.    getuser list states is: 2626978(v4.26b), or 2624290(v3.05).
  458.  
  459. 2: We then need to find the HIDING getuser value, which by looking at the
  460.    getuser list, we find is: 1101630 (For Port # 0, because we want to know
  461.    if this port is hiding FROM port 0).
  462.  
  463. 3: To find the OFFSET value, simply DROP the first two numbers from this
  464.    value, along with any preceeding zeroes, and we get: 1630
  465.  
  466. 4: We then convert the x6xxxxx in step 1 to an x4xxxxx, and use THIS value
  467.    in a getuser:
  468.  
  469.         pb=null() ; getuser 2426978 /* for CNet, v4.26b, or */
  470.         pb=null() ; getuser 2424290 /* for CNet, v3.05c BBS */
  471.  
  472.         a=import(offset(pb,result+1630),1) ; hide=BitTST(a,0)
  473.  
  474. 5: The "hide" variable would equal a "0" if the user on Port # 1 was NOT
  475.    hiding from you, or a "1" if they WERE hiding from you.
  476.  
  477. 6: The beauty of this whole process is that it's IMMEDIATE, regardless of
  478.    what Port # 1 happens to be doing when you "spy" on them! hehe
  479.  
  480. -----------------------------------------------------------------------------
  481.  
  482.     Lastly, it is also possible to WRITE information directly to MEMORY by
  483. using the STORAGE() command. In fact, every time you use the EA, EG, EL, etc.
  484. commands to make changes to these areas, the changes are being made to the
  485. data in MEMORY, and aren't written to disk until AFTER the user has logged
  486. off. Be VERY, VERY careful when using the STORAGE() command, because using a
  487. wrong value within this command could seriously damage your data files, or
  488. even guru your machine. The STORAGE() command is NOT meant for the beginner.
  489. Anyone can play around with the IMPORT() command. You won't hurt anything by
  490. simply READING the MEMORY, but only WRITE to MEMORY if you KNOW WHAT YOU ARE
  491. DOING! OK, with that "warning" out of the way, here's an example of using
  492. the STORAGE() command:
  493.  
  494.            Time Left This Call (Mins / by 10) ===> getuser 1200028
  495.  
  496.     Using the above getuser value, here's a routine that could be run from
  497. any port to automatically give the user on Port # 2 ten extra minutes of
  498. OnLine time: 
  499.  
  500.             1:  getuser 2426982  /* Use 2424294 on CNet, v3.05c */
  501.             2:  off=offset(null(),result+28)
  502.             3:  data=import(off,2)
  503.             4:  time=c2d(data)%10
  504.             5:  time=time+10
  505.             6:  time=d2c(time*10,2)
  506.             7:  data=storage(off,time,2)
  507.  
  508.             1:  getuser 2426982  /* Use 2424294 on CNet, v3.05c */
  509.              :
  510.              :  Get START of "PortData" structure.
  511.  
  512.             2:  off=offset(null(),result+28)
  513.              :
  514.              :  Create the proper OffSet Memory Location, per the given
  515.              :  1200028 getuser value.
  516.  
  517.             3:  data=import(off,2)
  518.              :
  519.              :  Read in the 2 bytes stored at this location. (Remember, we
  520.              :  have 2 bytes, because it's an x2xxxxx getuser value!)
  521.  
  522.             4:  time=c2d(data)%10
  523.              :
  524.              :  Convert this returned character to DECIMAL, then divide by
  525.              :  10 to get MINUTES left online.
  526.  
  527.             5:  time=time+10
  528.              :
  529.              :  Now ADD the extra 10 minutes to current value.
  530.  
  531.             6:  time=d2c(time*10,2)
  532.              :
  533.              :  Convert DECIMAL back into CHARACTER, but AFTER we multiply
  534.              :  by 10 to go back to TENTHS of MINUTES left online.
  535.  
  536.             7:  data=storage(off,time,2)
  537.              :
  538.              :  Write the 2 bytes back to MEMORY. Note the likeness between
  539.              :  this command, which WRITES the data, and the import() we
  540.              :  used in line 3 above. Only difference is the inclusion of
  541.              :  the "time" variable, as THIS is the data to be WRITTEN to
  542.              :  memory.
  543.  
  544.     The important thing to remember when using STORAGE() is to do things in
  545. the ABSOLUTE REVERSE of the way you IMPORT()'ed them. If you use C2D() to get
  546. a DECIMAL value to work with, make sure it goes BACK to a D2C(), etc. Using
  547. STORAGE(), instead of EXPORT() saves us from having to do TWO major jobs:
  548. having to repad text strings with "00"x's, and having to use the cryptic
  549. x2c() and d2x() commands to make the needed character value. Both are now
  550. unnecessary steps to the process! It can get a bit tricky, but if you TAKE
  551. YOUR TIME, and play around with the IMPORT() function FIRST, you can then
  552. MAKE SURE you are using the correct method to GET the value, BEFORE you try
  553. coding the STORAGE() which will then PUT the data(Remember, you won't hurt
  554. ANYTHING if you use IMPORT(), but you could do SEVERE damage with STORAGE(),
  555. unless you have a FIRM GRASP on these principles!)
  556.  
  557. -----------------------------------------------------------------------------
  558.  
  559.     Well, that'll put a cap on this discussion. I opted to store this info in
  560. it's own file, as it really only pertains to those interested in pursuing the
  561. ability to CODE, or PROGRAM, with these GetUser values.
  562.  
  563.     If you'd like some further examples on using any of the above methods,
  564. you can drop me some feedback via any of the following channels and I'll see
  565. what I can do to help you out. I'd rather HELP an aspiring programmer get at
  566. the solution than having to code it out completely myself. It helps ME, as
  567. well as the rest of the CNet population, as hopefully, it'll result in the
  568. creation of ANOTHER CNet ARexx Programmer, and we NEED as many of these as
  569. we can get ahold of! ;-)
  570.  
  571.     Via direct Internet EMail : dotoran@bluemoon.net
  572.        Via the World Wide Web : http://www.bluemoon.net/~dotoran/email.htm
  573.       Via the FidoNet Network : dotoran@1:260/121.0
  574.         Via the CLink Network : dotoran@911:6840/2.0
  575.      Via the ChipsNet Network : dotoran@546:7/1.0
  576.             Via Frontiers BBS : (716)/823-9892
  577.  
  578. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  579.                 This is the END, there "ain't" no more! ;-)
  580. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  581.